package com.usooft.metaTalent.core.wx.service.base;

import com.usooft.framework.core.query.Limit;
import com.usooft.framework.core.query.Page;
import com.usooft.metaTalent.core.wx.entity.WxOpenUser;
import com.usooft.metaTalent.core.wx.mapper.WxOpenUserMapper;
import com.usooft.metaTalent.core.wx.query.WxOpenUserQuery;
import com.usooft.metaTalent.core.wx.service.WxOpenUserService;
import com.usooft.metaTalent.core.wx.wrapper.WxOpenUserWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.OptimisticLockingFailureException;
import org.springframework.lang.NonNull;
import org.springframework.util.Assert;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;

public abstract class BaseWxOpenUserService implements WxOpenUserService {
    @Autowired
    private WxOpenUserMapper wxOpenUserMapper;

    @Override
    public WxOpenUser get(@NonNull Long id) {
        return find(id).orElseThrow();
    }

    @Override
    public Optional<WxOpenUser> find(@NonNull Long id) {
        return Optional.ofNullable(wxOpenUserMapper.get(id));
    }

    @Override
    public List<WxOpenUserWrapper> list(WxOpenUserQuery query) {
        return wxOpenUserMapper.list(query);
    }

    @Override
    public Page<WxOpenUserWrapper> page(WxOpenUserQuery query) {
        int rows = wxOpenUserMapper.count(query.getFilter());
        return new Page<>(rows, rows == 0 ? new ArrayList<>() : wxOpenUserMapper.list(query));
    }

    protected Optional<WxOpenUser> findOne(WxOpenUserQuery.Filter filter,
            WxOpenUserQuery.Sorts sorts) {
        List<WxOpenUserWrapper> wrappers = list(WxOpenUserQuery.builder()
                                .filter(filter)
                                .sorts(sorts)
                                .limit(Limit.rowCount(1))
                                .build());
        return wrappers.stream().findFirst().map(Function.identity());
    }

    protected Optional<WxOpenUser> findOne(WxOpenUserQuery.Filter filter) {
        return findOne(filter, WxOpenUserQuery.Sorts.builder().build());
    }

    @Override
    public int count(WxOpenUserQuery.Filter filter) {
        return wxOpenUserMapper.count(filter);
    }

    protected WxOpenUser internalAdd(String openId, String unionId) {
        WxOpenUser wxOpenUser = new WxOpenUser();
        wxOpenUser.setOpenId(openId);
        wxOpenUser.setUnionId(unionId);

        wxOpenUser.setCreatedDate(LocalDateTime.now());
        wxOpenUser.setVersion(0);
        wxOpenUserMapper.add(wxOpenUser);
        return wxOpenUser;
    }

    protected void internalUpdate(@NonNull WxOpenUser wxOpenUser) {
        wxOpenUser.setLastModifiedDate(LocalDateTime.now());

        int rows = wxOpenUserMapper.update(wxOpenUser);
        if (rows == 0) {
            throw new OptimisticLockingFailureException("更新失败。可能微信开放平台用户 (" + wxOpenUser.getId() + ") 的版本 (" + wxOpenUser.getVersion() + ") 已不是最新");
        }
        wxOpenUser.setVersion(wxOpenUser.getVersion() + 1);
    }

    protected void internalDelete(@NonNull WxOpenUser wxOpenUser) {
        int rows = wxOpenUserMapper.delete(wxOpenUser);
        if (rows == 0) {
            throw new OptimisticLockingFailureException("删除失败。可能微信开放平台用户 (" + wxOpenUser.getId() + ") 的版本 (" + wxOpenUser.getVersion() + ") 已不是最新");
        }
    }

    @Override
    public Optional<? extends WxOpenUser> findByOpenId(@NonNull String openId) {
        Assert.notNull(openId, "必须提供OpenID");
        return findOne(WxOpenUserQuery.Filter.builder()
                .openIdIs(openId)
                .build());
    }
}
